#include "webglk.h"
#include <stdio.h>
#include <stdlib.h>

extern glui32 screenwidth,screenheight,font3width,font3height,font4width,font4height;
static window_t windows[100];

static void layoutWindow(winid_t);

void glk_set_window(winid_t win)
{
	if (!win) glk_stream_set_current(0);
	else glk_stream_set_current(windows[win].str);
}
winid_t glk_window_get_root()
{
	int i;
	// find any active window
	for (i=1;i<100;i++)
	{
		if (windows[i].inuse)
			break;
	}
	if (i==100) return 0;
	// then find the root from that.
	while (windows[i].parent) i=windows[i].parent;
	return i;
}
glui32 glk_window_get_rock(winid_t win)
{
	if (windows[win].inuse) return windows[win].rock;
	return 0;
}
void glk_window_clear(winid_t win)
{
	glk_stream_buffer_flush();
	printf("{m:'clearwin',w:%u},\n",win);
}
static void closeWindow(winid_t win)
{
	glk_stream_close(windows[win].str,NULL);
	windows[win].inuse=0;
	if (windows[win].type==wintype_Pair)
	{
		closeWindow(windows[win].child1);
		closeWindow(windows[win].child2);
	}
	else
		printf("{m:'close',w:%u},\n",win);
}
void glk_window_close(winid_t win,stream_result_t *result)
{
	glui32 p=windows[win].parent;
	glk_stream_close(windows[win].str,result);
	closeWindow(win);
	if (p)
	{
		glui32 gp,n;

		windows[p].inuse=0;
		glk_stream_close(windows[p].str,NULL);

		if (windows[p].child1==win) n=windows[p].child2;
		else n=windows[p].child1;

		gp=windows[p].parent;
		if (gp)
		{
			if (windows[gp].child1==p) windows[gp].child1=n;
			else windows[gp].child2=n;
			windows[n].parent=gp;
			layoutWindow(gp);
		}
		else
		{
			windows[n].parent=0;
			windows[n].width=screenwidth;
			windows[n].height=screenheight;
			windows[n].x=0;
			windows[n].y=0;
			if (windows[n].type==wintype_Pair)
				layoutWindow(n);
			else
				printf("{m:'resize',i:%u,x:0,y:0,w:%u,h:%u},\n",n,screenwidth,screenheight);
		}
	}
}

void glk_window_get_size(winid_t win,glui32 *widthptr,glui32 *heightptr)
{
	glui32 w,h;
	if (windows[win].type==wintype_TextBuffer)
	{
		w=windows[win].width/font3width;
		h=windows[win].height/font3height;
	}
	else if (windows[win].type==wintype_TextGrid)
	{
		w=windows[win].width/font4width;
		h=windows[win].height/font4height;
	}
	else if (windows[win].type==wintype_Graphics)
	{
		w=windows[win].width;
		h=windows[win].height;
	}
	else fatal("Get size of unknown type %d",windows[win].type);
	if (widthptr) *widthptr=w;
	if (heightptr) *heightptr=h;
}
glui32 glk_window_get_type(winid_t win)
{
	return windows[win].type;
}
winid_t glk_window_get_parent(winid_t win)
{
	return windows[win].parent;
}
void glk_window_move_cursor(winid_t win,glui32 xpos,glui32 ypos)
{
	glk_stream_buffer_flush();
	printf("{m:'move',w:%u,x:%u,y:%u},\n",win,xpos,ypos);
}
winid_t glk_window_iterate(winid_t win,glui32 *rock)
{
	winid_t i;
	for (i=win+1;i<100;i++)
	{
		if (windows[i].inuse)
		{
			if (rock) *rock=windows[i].rock;
			return i;
		}
	}
	if (rock) *rock=0;
	return 0;
}
static winid_t newWindow()
{
	int i;
	for (i=1;i<100;i++)
		if (!windows[i].inuse)
		{
			windows[i].inuse=1;
			windows[i].parent=windows[i].child1=windows[i].child2=0;
			windows[i].str=glk_stream_new_window(i);
			return i;
		}
	return 0;
}

winid_t glk_window_open(winid_t splitwin,glui32 method,glui32 size,glui32 wintype,glui32 rock)
{
	winid_t win=newWindow();
	windows[win].rock=rock;
	windows[win].type=wintype;

	if (splitwin)
	{
		winid_t oldp;
		winid_t pair=newWindow();
		windows[pair].type=wintype_Pair;
		windows[pair].method=method;
		windows[pair].size=size;
		windows[pair].child1=splitwin;
		windows[pair].child2=win;
		windows[pair].key=win;
		oldp=windows[splitwin].parent;
		windows[splitwin].parent=pair;
		windows[win].parent=pair;
		windows[pair].parent=oldp;

		windows[pair].x=windows[splitwin].x;
		windows[pair].y=windows[splitwin].y;
		windows[pair].width=windows[splitwin].width;
		windows[pair].height=windows[splitwin].height;

		if (oldp)
		{
			if (windows[oldp].child1==splitwin)
				windows[oldp].child1=pair;
			else
				windows[oldp].child2=pair;
		}
		printf("{m:'newwindow',i:%u,x:0,y:0,w:0,h:0,t:%u},\n",win,windows[win].type);
		layoutWindow(pair);
	}
	else
	{
		windows[win].width=screenwidth;
		windows[win].height=screenheight;
		windows[win].x=0;
		windows[win].y=0;
		printf("{m:'newwindow',i:%u,x:%u,y:%u,w:%u,h:%u,t:%u},\n",win,windows[win].x,windows[win].y,windows[win].width,windows[win].height,windows[win].type);
	}
	return win;
}
static void layoutWindow(winid_t win)
{
	glui32 size;
	window_t *w=&windows[win];
	glui32 dir=w->method&winmethod_DirMask;

	if ((w->method&winmethod_DivisionMask)==winmethod_Fixed)
	{
		size=w->size;
		if (dir<2)
		{
			switch (windows[w->key].type)
			{
				case wintype_TextGrid: size*=font4width; break;
				case wintype_TextBuffer: size*=font3width; break;
				case wintype_Graphics: break;
				default: fatal("unknown resize type %d",windows[w->key].type);
			}
		}
		else
		{
			switch (windows[w->key].type)
			{
				case wintype_TextGrid: size*=font4height; break;
				case wintype_TextBuffer: size*=font3height; break;
				case wintype_Graphics: break;
				default: fatal("unknown resize type %d",windows[w->key].type);
			}
		}
	}
	else
	{
		if (dir<2) size=(w->size*w->width)/100;
		else size=(w->size*w->height)/100;
	}
	switch (dir)
	{
		case winmethod_Left:
			windows[w->child1].width=w->width-size;
			windows[w->child1].height=w->height;
			windows[w->child1].x=w->x+size;
			windows[w->child1].y=w->y;
			windows[w->child2].width=size;
			windows[w->child2].height=w->height;
			windows[w->child2].x=w->x;
			windows[w->child2].y=w->y;
			break;
		case winmethod_Right:
			windows[w->child1].width=w->width-size;
			windows[w->child1].height=w->height;
			windows[w->child1].x=w->x;
			windows[w->child1].y=w->y;
			windows[w->child2].width=size;
			windows[w->child2].height=w->height;
			windows[w->child2].x=w->x+(w->width-size);
			windows[w->child2].y=w->y;
			break;
		case winmethod_Above:
			windows[w->child1].width=w->width;
			windows[w->child1].height=w->height-size;
			windows[w->child1].x=w->x;
			windows[w->child1].y=w->y+size;
			windows[w->child2].width=w->width;
			windows[w->child2].height=size;
			windows[w->child2].x=w->x;
			windows[w->child2].y=w->y;
			break;
		case winmethod_Below:
			windows[w->child1].width=w->width;
			windows[w->child1].height=w->height-size;
			windows[w->child1].x=w->x;
			windows[w->child1].y=w->y;
			windows[w->child2].width=w->width;
			windows[w->child2].height=size;
			windows[w->child2].x=w->x;
			windows[w->child2].y=w->y+(w->height-size);
			break;
	}
	window_t *c=&windows[w->child1];
	if (c->type==wintype_Pair)
		layoutWindow(w->child1);
	else
		printf("{m:'resize',i:%u,x:%u,y:%u,w:%u,h:%u},\n",w->child1,c->x,c->y,c->width,c->height);
	c=&windows[w->child2];
	if (c->type==wintype_Pair)
		layoutWindow(w->child2);
	else
		printf("{m:'resize',i:%u,x:%u,y:%u,w:%u,h:%u},\n",w->child2,c->x,c->y,c->width,c->height);
}
void glk_window_set_arrangement(winid_t win,glui32 method,glui32 size,winid_t keywin)
{
	windows[win].method=method;
	windows[win].size=size;
	if (keywin) windows[win].key=keywin;
	layoutWindow(win);
}
void glk_window_set_background_color(winid_t win,glui32 color)
{
	printf("{m:'setbackground',w:%u,b:'#%02x%02x%02x'},\n",win,color>>16,(color>>8)&0xff,color&0x0ff);
}
void glk_window_fill_rect(winid_t win,glui32 color,glsi32 left,glsi32 top,glui32 width,glui32 height)
{
	printf("{m:'fillrect',i:%u,b:'#%02x%02x%02x',x:%u,y:%u,w:%u,h:%u},\n",win,color>>16,(color>>8)&0xff,color&0xff,left,top,width,height);
}

void glk_window_load(FILE *f)
{
	fread(&screenwidth,sizeof(glui32),1,f);
	fread(&screenheight,sizeof(glui32),1,f);
	fread(&font3width,sizeof(glui32),1,f);
	fread(&font3height,sizeof(glui32),1,f);
	fread(&font4width,sizeof(glui32),1,f);
	fread(&font4height,sizeof(glui32),1,f);
	fread(windows,sizeof(windows),1,f);
}
void glk_window_save(FILE *f)
{
	fwrite(&screenwidth,sizeof(glui32),1,f);
	fwrite(&screenheight,sizeof(glui32),1,f);
	fwrite(&font3width,sizeof(glui32),1,f);
	fwrite(&font3height,sizeof(glui32),1,f);
	fwrite(&font4width,sizeof(glui32),1,f);
	fwrite(&font4height,sizeof(glui32),1,f);
	fwrite(windows,sizeof(windows),1,f);
}
